# ReflectionTexture - Cairo based texture that can be used as reflection
# Copyright (C) 2007 Lauri Taimila
# 
# Entertainer is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# Entertainer is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

__licence__ = "GPLv2"
__copyright__ = "2008, Lauri Taimila"
__author__ = "Lauri Taimila <lauri@taimila.com>"

import gtk
import cairo
import clutter
from clutter.cluttercairo import CairoTexture

class ReflectionTexture(CairoTexture):
    """
    Reflection texture
    
    This texture can be used as reflection to another texture. This texture
    is rendered with Cairo.
    """
    
    def __init__(self, pixbuf, width, height, ref_height=0.3, opacity=0.3, round_corners=False, margin=1, radius=15):
        """
        Create a new reflection texture
        
        @param pixbuf: gtk.gdk.Pixbuf object. Graphics for texture
        @param height: Height of the reflection in percents (0-1). Realtive to image height
        @param opacity: Highest opacity level in reflection (0-1)
        @param round_conrners: Boolean, do we add rounded corners
        @param margin: number of pixels to cut off from sides
        @param radius: Radius for rounded corners
        """       
        CairoTexture.__init__(self, width, height)
        context = self.cairo_create()
        ct = gtk.gdk.CairoContext(context)
        
        # Round corners
        if round_corners:
            x = 0 + margin
            y = 0 + margin
            w1 = width - (margin * 2)
            h1 = height - (margin * 2)
            self.roundedCorners(context, x ,y, w1, h1, radius, radius)
        
        # Scale context area
        wr = width / float(pixbuf.get_width())
        hr = height / float(pixbuf.get_height())
        context.scale(wr,hr)
        
        # Create gradient mask
        self.gradient = cairo.LinearGradient(0, 0, 0, pixbuf.get_height())
        self.gradient.add_color_stop_rgba(1 - ref_height, 1, 1, 1, 0)
        self.gradient.add_color_stop_rgba(1, 0, 0, 0, opacity)

        ct.set_source_pixbuf(pixbuf,0,0)
        context.mask(self.gradient)
        
        del context # Update texture
        del ct
        
        self.set_anchor_point_from_gravity(clutter.GRAVITY_SOUTH_WEST)
        self.set_rotation(clutter.Z_AXIS, 180,0,0,0)
        self.set_rotation(clutter.Y_AXIS, 180,0,0,0)
        
    def roundedCorners(self, context, x, y, w, h, radius_x, radius_y):
        """
        Clip cairo texture with rounded rectangle.
        """
        ARC_TO_BEZIER = 0.55228475
        if radius_x > w - radius_x:
            radius_x = w / 2
        if radius_y > h - radius_y:
            radius_y = h / 2

        #approximate (quite close) the arc using a bezier curve
        c1 = ARC_TO_BEZIER * radius_x
        c2 = ARC_TO_BEZIER * radius_y

        context.new_path();
        context.move_to ( x + radius_x, y)
        context.rel_line_to ( w - 2 * radius_x, 0.0)
        context.rel_curve_to ( c1, 0.0, radius_x, c2, radius_x, radius_y)
        context.rel_line_to ( 0, h - 2 * radius_y)
        context.rel_curve_to ( 0.0, c2, c1 - radius_x, radius_y, -radius_x, radius_y)
        context.rel_line_to ( -w + 2 * radius_x, 0)
        context.rel_curve_to ( -c1, 0, -radius_x, -c2, -radius_x, -radius_y)
        context.rel_line_to (0, -h + 2 * radius_y)
        context.rel_curve_to (0.0, -c2, radius_x - c1, -radius_y, radius_x, -radius_y)
        context.close_path()
        context.clip()
